package service

import (
	"context"
	"errors"
	"gf2DemoServer/internal/model"
	"gf2DemoServer/internal/model/entity"
	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/golang-jwt/jwt/v4"
	"time"
)

var (
	// JwtSecret 加密密钥
	secret = []byte("o6B!DiY&8ysdB4#llhmc1@dWvjf9bJN@")
)

type sToken struct{}

var insToken *sToken

func Token() *sToken {
	if insToken == nil {
		insToken = &sToken{}
	}
	return insToken
}

// MyClaims 数据
type MyClaims struct {
	*model.UserTokenData
	jwt.RegisteredClaims
}

// Build 创建sToken
func (s *sToken) Build(ctx context.Context, user *entity.User) (sTokenString string, err error) {
	claim := MyClaims{
		UserTokenData: &model.UserTokenData{
			UserId:    user.Id,
			Mobile:    user.Mobile,
			LoginIp:   g.RequestFromCtx(ctx).GetClientIp(),
			LoginTime: time.Now().Unix(),
		},
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(6 * time.Hour * time.Duration(1))),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			NotBefore: jwt.NewNumericDate(time.Now()),
		}}
	sToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claim)
	sTokenString, err = sToken.SignedString(secret)
	return
}

// Parse 解析sToken
func (s *sToken) Parse(ctx context.Context, sTokenString string) (*MyClaims, error) {
	sToken, err := jwt.ParseWithClaims(sTokenString, &MyClaims{}, func(sToken *jwt.Token) (interface{}, error) {
		return secret, nil
	})
	if err == nil {
		if claims, ok := sToken.Claims.(*MyClaims); ok && sToken.Valid {
			return claims, nil
		}
	}
	return nil, errors.New("登录凭据已失效")
}

// Check 校验sToken
func (s *sToken) Check(ctx context.Context, forceValidate bool) *MyClaims {
	r := g.RequestFromCtx(ctx)
	myClaims, err := s.Parse(ctx, r.GetHeader("Token"))
	if err != nil && forceValidate {
		r.Response.WriteJsonExit(ghttp.DefaultHandlerResponse{
			Code:    gcode.CodeNotAuthorized.Code(),
			Message: "请先登录",
			Data:    nil,
		})
	}
	return myClaims
}
